package com.mavenq.fly.utils.excelv4;

import com.mavenq.fly.utils.excelv4.config.ExcelExportConfig;
import com.mavenq.fly.utils.excelv4.config.ExcelImportConfig;
import com.mavenq.fly.utils.excelv4.config.PageReadConfig;
import com.mavenq.fly.utils.excelv4.exception.ExcelImportException;
import com.mavenq.fly.utils.excelv4.model.ExcelFileInfo;
import com.mavenq.fly.utils.excelv4.model.ImportErrorDetail;
import com.mavenq.fly.utils.excelv4.model.ImportResult;
import com.mavenq.fly.utils.excelv4.model.PageReadResult;
import com.mavenq.fly.utils.excelv4.processor.BusinessValidator;
import com.mavenq.fly.utils.excelv4.processor.CellValueConverter;
import com.mavenq.fly.utils.excelv4.processor.FieldValidator;
import com.mavenq.fly.utils.excelv4.processor.PageDataProcessor;
import com.mavenq.fly.utils.excelv4.processor.StreamingDataProcessor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import java.io.*;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 完整的Excel工具类
 */
public class ExcelUtil {
    
    // ==================== 常量定义 ====================
    private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private static final int DEFAULT_COLUMN_WIDTH = 15;
    private static final int MIN_COLUMN_WIDTH = 8;
    private static final int MAX_COLUMN_WIDTH = 50;
    private static final short DEFAULT_ROW_HEIGHT = 400;
    private static final short HEADER_ROW_HEIGHT = 500;
    
    private static final ExecutorService BACKGROUND_EXECUTOR = 
        Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    
    // ==================== 导出相关方法 ====================
    
    public static <T> void exportToExcel(List<T> dataList, String[] headers, String[] fieldNames,
                                        String sheetName, OutputStream outputStream, boolean isXlsx) {
        Workbook workbook = null;
        try {
            workbook = isXlsx ? new XSSFWorkbook() : new HSSFWorkbook();
            Sheet sheet = workbook.createSheet(sheetName != null ? sheetName : "Sheet1");
            
            setDefaultColumnWidth(sheet, headers.length);
            
            CellStyle headerStyle = createHeaderStyle(workbook);
            CellStyle dataStyle = createDataStyle(workbook);
            
            Row headerRow = sheet.createRow(0);
            headerRow.setHeight(HEADER_ROW_HEIGHT);
            
            for (int i = 0; i < headers.length; i++) {
                Cell cell = headerRow.createCell(i);
                cell.setCellValue(headers[i]);
                cell.setCellStyle(headerStyle);
            }
            
            if (dataList != null && !dataList.isEmpty()) {
                int rowNum = 1;
                for (T data : dataList) {
                    Row row = sheet.createRow(rowNum++);
                    row.setHeight(DEFAULT_ROW_HEIGHT);
                    fillRowData(row, data, fieldNames, dataStyle);
                }
            }
            
            autoSizeColumns(sheet, headers.length, dataList, fieldNames);
            workbook.write(outputStream);
            
        } catch (Exception e) {
            throw new RuntimeException("导出Excel失败", e);
        } finally {
            closeWorkbook(workbook);
        }
    }
    
    public static <T> void exportToExcelAdvanced(List<T> dataList, String[] headers, String[] fieldNames,
                                                String sheetName, OutputStream outputStream, 
                                                boolean isXlsx, ExcelExportConfig config) {
        Workbook workbook = null;
        try {
            workbook = isXlsx ? new XSSFWorkbook() : new HSSFWorkbook();
            Sheet sheet = workbook.createSheet(sheetName != null ? sheetName : "Sheet1");
            
            setDefaultColumnWidth(sheet, headers.length, config.getDefaultColumnWidth());
            
            CellStyle headerStyle = createCustomHeaderStyle(workbook, config);
            CellStyle dataStyle = createCustomDataStyle(workbook, config);
            
            Row headerRow = sheet.createRow(0);
            headerRow.setHeight(config.getHeaderRowHeight());
            
            for (int i = 0; i < headers.length; i++) {
                Cell cell = headerRow.createCell(i);
                cell.setCellValue(headers[i]);
                cell.setCellStyle(headerStyle);
            }
            
            if (dataList != null && !dataList.isEmpty()) {
                int rowNum = 1;
                for (T data : dataList) {
                    Row row = sheet.createRow(rowNum++);
                    row.setHeight(config.getDataRowHeight());
                    fillRowData(row, data, fieldNames, dataStyle);
                }
            }
            
            if (config.isAutoSizeColumns()) {
                autoSizeColumns(sheet, headers.length, dataList, fieldNames, 
                              config.getMinColumnWidth(), config.getMaxColumnWidth());
            }
            
            workbook.write(outputStream);
            
        } catch (Exception e) {
            throw new RuntimeException("导出Excel失败", e);
        } finally {
            closeWorkbook(workbook);
        }
    }
    
    // ==================== 导入相关方法 ====================
    
    public static <T> List<T> importFromExcel(InputStream inputStream, String[] headers, 
                                             String[] fieldNames, Class<T> clazz, boolean isXlsx) {
        ExcelImportConfig<T> config = new ExcelImportConfig<>(clazz).expectedHeaders(headers);
        
        for (int i = 0; i < headers.length && i < fieldNames.length; i++) {
            config.columnMapping(headers[i], fieldNames[i]);
        }
        
        return importExcel(inputStream, config, isXlsx);
    }
    
    public static <T> List<T> importExcel(InputStream inputStream, 
                                         ExcelImportConfig<T> config, 
                                         boolean isXlsx) {
        List<T> resultList = new ArrayList<>();
        Workbook workbook = null;
        
        try {
            workbook = isXlsx ? new XSSFWorkbook(inputStream) : new HSSFWorkbook(inputStream);
            Sheet sheet = workbook.getSheetAt(config.getStartSheetIndex());
            
            if (sheet == null) {
                throw new RuntimeException("Excel文件中没有工作表");
            }
            
            Map<Integer, String> columnFieldMap = parseHeaderAndCreateMapping(sheet, config);
            
            if (columnFieldMap.isEmpty()) {
                throw new RuntimeException("无法建立列映射关系");
            }
            
            int startRow = Math.max(config.getStartRow(), 0);
            int endRow = Math.min(sheet.getLastRowNum(), config.getEndRow());
            
            for (int i = startRow; i <= endRow; i++) {
                Row row = sheet.getRow(i);
                if (row == null || isEmptyRow(row)) continue;
                
                try {
                    T obj = parseRowToObject(row, columnFieldMap, config, sheet.getSheetName(), new ArrayList<>());
                    if (obj != null) {
                        resultList.add(obj);
                        if (config.getImportListener() != null) {
                            config.getImportListener().onRowImported(obj, i);
                        }
                    }
                } catch (Exception e) {
                    if (config.getImportListener() != null) {
                        config.getImportListener().onRowError(i, e);
                    }
                }
            }
            
        } catch (Exception e) {
            throw new RuntimeException("导入Excel失败", e);
        } finally {
            closeWorkbook(workbook);
            closeStream(inputStream);
        }
        
        return resultList;
    }
    
    public static <T> ImportResult<T> importExcelWithValidation(InputStream inputStream, 
                                                               ExcelImportConfig<T> config, 
                                                               boolean isXlsx) {
        List<T> successData = new ArrayList<>();
        List<ImportErrorDetail> errors = new ArrayList<>();
        Workbook workbook = null;
        String sheetName = "";
        int totalRows = 0;
        int successCount = 0;
        int errorCount = 0;
        
        try {
            workbook = isXlsx ? new XSSFWorkbook(inputStream) : new HSSFWorkbook(inputStream);
            Sheet sheet = workbook.getSheetAt(config.getStartSheetIndex());
            sheetName = sheet.getSheetName();
            totalRows = sheet.getLastRowNum();
            
            Map<Integer, String> columnFieldMap = parseHeaderAndCreateMapping(sheet, config);
            
            if (columnFieldMap.isEmpty()) {
                errors.add(new ImportErrorDetail(0, 0, sheetName, "", "", 
                    "无法建立列映射关系", ImportErrorDetail.ErrorType.DATA_FORMAT_ERROR));
                return new ImportResult<>(successData, errors, totalRows, 0, errors.size());
            }
            
            int startRow = Math.max(config.getStartRow(), 0);
            int endRow = Math.min(sheet.getLastRowNum(), config.getEndRow());
            
            for (int i = startRow; i <= endRow; i++) {
                Row row = sheet.getRow(i);
                if (row == null || isEmptyRow(row)) continue;
                
                List<ImportErrorDetail> rowErrors = new ArrayList<>();
                T obj = null;
                
                try {
                    obj = parseRowToObject(row, columnFieldMap, config, sheetName, rowErrors);
                    
                    if (obj != null && rowErrors.isEmpty()) {
                        performBusinessValidation(obj, i, config, rowErrors);
                        
                        if (rowErrors.isEmpty()) {
                            successData.add(obj);
                            successCount++;
                            if (config.getImportListener() != null) {
                                config.getImportListener().onRowImported(obj, i);
                            }
                        } else {
                            errors.addAll(rowErrors);
                            errorCount++;
                        }
                    } else {
                        errors.addAll(rowErrors);
                        errorCount++;
                    }
                    
                } catch (Exception e) {
                    errorCount++;
                    errors.add(new ImportErrorDetail(i, 0, sheetName, "", "", 
                        "行解析异常: " + e.getMessage(), ImportErrorDetail.ErrorType.DATA_FORMAT_ERROR));
                }
            }
            
            if (config.getImportListener() != null) {
                config.getImportListener().onComplete(successCount, errorCount);
            }
            
        } catch (Exception e) {
            errors.add(new ImportErrorDetail(0, 0, sheetName, "", "", 
                "导入过程异常: " + e.getMessage(), ImportErrorDetail.ErrorType.DATA_FORMAT_ERROR));
        } finally {
            closeWorkbook(workbook);
            closeStream(inputStream);
        }
        
        return new ImportResult<>(successData, errors, totalRows, successCount, errors.size());
    }
    
    // ==================== 固定行读取方法 ====================
    
    public static <T> List<T> importFromFixedRow(InputStream inputStream, 
                                                ExcelImportConfig<T> config, 
                                                boolean isXlsx) {
        return importExcel(inputStream, config, isXlsx);
    }
    
    public static <T> ImportResult<T> importFromFixedRowWithValidation(InputStream inputStream, 
                                                                      ExcelImportConfig<T> config, 
                                                                      boolean isXlsx) {
        return importExcelWithValidation(inputStream, config, isXlsx);
    }
    
    // ==================== 分页读取方法 ====================
    
    public static <T> PageReadResult<T> readPage(InputStream inputStream, 
                                                ExcelImportConfig<T> config,
                                                int page, int pageSize, 
                                                boolean isXlsx) {
        Workbook workbook = null;
        try {
            workbook = isXlsx ? new XSSFWorkbook(inputStream) : new HSSFWorkbook(inputStream);
            Sheet sheet = workbook.getSheetAt(config.getStartSheetIndex());
            String sheetName = sheet.getSheetName();
            
            Map<Integer, String> columnFieldMap = parseHeaderAndCreateMapping(sheet, config);
            
            int startRow = calculateStartRowFromFixedRow(page, pageSize, config.getStartRow());
            int endRow = calculateEndRowFromFixedRow(sheet, startRow, pageSize, config.getEndRow());
            
            List<T> pageData = new ArrayList<>();
            List<ImportErrorDetail> pageErrors = new ArrayList<>();
            
            for (int i = startRow; i <= endRow; i++) {
                Row row = sheet.getRow(i);
                if (row == null || isEmptyRow(row)) continue;
                
                try {
                    T obj = parseRowToObject(row, columnFieldMap, config, sheetName, new ArrayList<>());
                    if (obj != null) {
                        pageData.add(obj);
                    }
                } catch (Exception e) {
                    pageErrors.add(new ImportErrorDetail(i, 0, sheetName, "", "", 
                        "行解析异常: " + e.getMessage(), ImportErrorDetail.ErrorType.DATA_FORMAT_ERROR));
                }
            }
            
            long totalRows = Math.min(sheet.getLastRowNum(), config.getEndRow()) - config.getStartRow() + 1;
            ImportResult<T> importResult = new ImportResult<>(pageData, pageErrors, 
                (int) totalRows, pageData.size(), pageErrors.size());
            
            return new PageReadResult<>(pageData, page, pageSize, totalRows, importResult);
            
        } catch (Exception e) {
            throw new RuntimeException("分页读取Excel失败: " + e.getMessage(), e);
        } finally {
            closeWorkbook(workbook);
        }
    }
    
    public static <T> ImportResult<T> readStreaming(InputStream inputStream,
                                                   ExcelImportConfig<T> config,
                                                   StreamingDataProcessor<T> processor,
                                                   boolean isXlsx) {
        Workbook workbook = null;
        List<ImportErrorDetail> allErrors = new ArrayList<>();
        long successCount = 0;
        long totalRows = 0;
        
        try {
            workbook = isXlsx ? new XSSFWorkbook(inputStream) : new HSSFWorkbook(inputStream);
            Sheet sheet = workbook.getSheetAt(config.getStartSheetIndex());
            String sheetName = sheet.getSheetName();
            totalRows = sheet.getLastRowNum();
            
            Map<Integer, String> columnFieldMap = parseHeaderAndCreateMapping(sheet, config);
            
            List<T> batchBuffer = new ArrayList<>();
            int batchSize = 100;
            int startRow = Math.max(config.getStartRow(), 1);
            int endRow = Math.min(sheet.getLastRowNum(), config.getEndRow());
            
            for (int i = startRow; i <= endRow; i++) {
                Row row = sheet.getRow(i);
                if (row == null || isEmptyRow(row)) continue;
                
                try {
                    T obj = parseRowToObject(row, columnFieldMap, config, sheetName, new ArrayList<>());
                    if (obj != null) {
                        batchBuffer.add(obj);
                        
                        if (batchBuffer.size() >= batchSize) {
                            processBatch(batchBuffer, processor, i - batchSize + 1);
                            successCount += batchBuffer.size();
                            batchBuffer.clear();
                        }
                    }
                } catch (Exception e) {
                    allErrors.add(new ImportErrorDetail(i, 0, sheetName, "", "", 
                        "行解析异常: " + e.getMessage(), ImportErrorDetail.ErrorType.DATA_FORMAT_ERROR));
                }
            }
            
            if (!batchBuffer.isEmpty()) {
                processBatch(batchBuffer, processor, (int) (totalRows - batchBuffer.size() + 1));
                successCount += batchBuffer.size();
            }
            
            processor.onComplete(totalRows, successCount);
            
        } catch (Exception e) {
            processor.onError(e);
            throw new RuntimeException("流式读取Excel失败: " + e.getMessage(), e);
        } finally {
            closeWorkbook(workbook);
            closeStream(inputStream);
        }
        
        return new ImportResult<>(Collections.emptyList(), allErrors, 
            (int) totalRows, (int) successCount, allErrors.size());
    }
    
    public static <T> CompletableFuture<ImportResult<T>> readAsync(InputStream inputStream,
                                                                  ExcelImportConfig<T> config,
                                                                  PageDataProcessor<T> processor,
                                                                  PageReadConfig pageConfig,
                                                                  boolean isXlsx) {
        return CompletableFuture.supplyAsync(() -> {
            return readWithPaging(inputStream, config, processor, pageConfig, isXlsx);
        }, BACKGROUND_EXECUTOR);
    }
    
    public static <T> ImportResult<T> readWithPaging(InputStream inputStream,
                                                    ExcelImportConfig<T> config,
                                                    PageDataProcessor<T> processor,
                                                    PageReadConfig pageConfig,
                                                    boolean isXlsx) {
        Workbook workbook = null;
        List<ImportErrorDetail> allErrors = new ArrayList<>();
        long totalSuccess = 0;
        long totalErrors = 0;
        long totalRows = 0;
        
        try {
            workbook = isXlsx ? new XSSFWorkbook(inputStream) : new HSSFWorkbook(inputStream);
            Sheet sheet = workbook.getSheetAt(config.getStartSheetIndex());
            totalRows = Math.min(sheet.getLastRowNum(), pageConfig.getMaxRows());
            
            Map<Integer, String> columnFieldMap = parseHeaderAndCreateMapping(sheet, config);
            
            int totalPages = (int) Math.ceil((double) totalRows / pageConfig.getPageSize());
            
            for (int page = 1; page <= totalPages; page++) {
                int startRow = calculateStartRowFromFixedRow(page, pageConfig.getPageSize(), config.getStartRow());
                int endRow = calculateEndRowFromFixedRow(sheet, startRow, pageConfig.getPageSize(), config.getEndRow());
                
                List<T> pageData = new ArrayList<>();
                List<ImportErrorDetail> pageErrors = new ArrayList<>();
                
                for (int i = startRow; i <= endRow; i++) {
                    Row row = sheet.getRow(i);
                    if (row == null || isEmptyRow(row)) continue;
                    
                    try {
                        T obj = parseRowToObject(row, columnFieldMap, config, sheet.getSheetName(), new ArrayList<>());
                        if (obj != null) {
                            pageData.add(obj);
                        }
                    } catch (Exception e) {
                        pageErrors.add(new ImportErrorDetail(i, 0, sheet.getSheetName(), "", "", 
                            "行解析异常: " + e.getMessage(), ImportErrorDetail.ErrorType.DATA_FORMAT_ERROR));
                    }
                }
                
                ImportResult<T> pageResult = new ImportResult<>(pageData, pageErrors, 
                    pageData.size(), pageData.size(), pageErrors.size());
                
                PageReadResult<T> pageInfo = new PageReadResult<>(pageData, page,
                    pageConfig.getPageSize(), totalRows, pageResult);
                
                boolean success = processor.processPage(pageData, pageInfo);
                
                if (success) {
                    totalSuccess += pageData.size();
                }
                totalErrors += pageErrors.size();
                allErrors.addAll(pageErrors);
                
                System.out.printf("处理进度: %d/%d 页 (%.1f%%)%n", 
                    page, totalPages, (page * 100.0 / totalPages));
            }
            
            processor.onComplete(totalRows, totalSuccess, totalErrors);
            
        } catch (Exception e) {
            processor.onError(e);
            throw new RuntimeException("分页读取Excel失败: " + e.getMessage(), e);
        } finally {
            closeWorkbook(workbook);
            closeStream(inputStream);
        }
        
        return new ImportResult<>(Collections.emptyList(), allErrors,
            (int) totalRows, (int) totalSuccess, (int) totalErrors);
    }
    
    // ==================== 工具方法 ====================
    
    public static void mergeCells(Sheet sheet, int firstRow, int lastRow, int firstCol, int lastCol) {
        sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol));
    }
    
    public static long estimateMemoryUsage(int rowCount, int columnCount) {
        long baseMemory = rowCount * columnCount * 1024L;
        long poiOverhead = rowCount * 500L;
        return baseMemory + poiOverhead;
    }
    
    public static boolean isFileTooLarge(File file, long maxSizeMB) {
        long maxSizeBytes = maxSizeMB * 1024 * 1024;
        return file.length() > maxSizeBytes;
    }
    
    public static ExcelFileInfo getFileInfo(InputStream inputStream, boolean isXlsx) {
        Workbook workbook = null;
        try {
            workbook = isXlsx ? new XSSFWorkbook(inputStream) : new HSSFWorkbook(inputStream);
            Sheet sheet = workbook.getSheetAt(0);
            
            ExcelFileInfo info = new ExcelFileInfo();
            info.setSheetName(sheet.getSheetName());
            info.setRowCount(sheet.getLastRowNum());
            info.setColumnCount(getMaxColumnCount(sheet));
            info.setFileType(isXlsx ? "xlsx" : "xls");
            
            return info;
        } catch (Exception e) {
            throw new RuntimeException("获取文件信息失败", e);
        } finally {
            closeWorkbook(workbook);
        }
    }
    
    public static List<String> getSheetNames(InputStream inputStream, boolean isXlsx) {
        Workbook workbook = null;
        try {
            workbook = isXlsx ? new XSSFWorkbook(inputStream) : new HSSFWorkbook(inputStream);
            List<String> sheetNames = new ArrayList<>();
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                sheetNames.add(workbook.getSheetName(i));
            }
            return sheetNames;
        } catch (Exception e) {
            throw new RuntimeException("获取工作表列表失败", e);
        } finally {
            closeWorkbook(workbook);
        }
    }
    
    // ==================== 私有方法 ====================
    
    private static void setDefaultColumnWidth(Sheet sheet, int columnCount) {
        setDefaultColumnWidth(sheet, columnCount, DEFAULT_COLUMN_WIDTH);
    }
    
    private static void setDefaultColumnWidth(Sheet sheet, int columnCount, int width) {
        for (int i = 0; i < columnCount; i++) {
            sheet.setColumnWidth(i, width * 256);
        }
    }
    
    private static <T> void autoSizeColumns(Sheet sheet, int columnCount, List<T> dataList, String[] fieldNames) {
        autoSizeColumns(sheet, columnCount, dataList, fieldNames, MIN_COLUMN_WIDTH, MAX_COLUMN_WIDTH);
    }
    
    private static <T> void autoSizeColumns(Sheet sheet, int columnCount, List<T> dataList, 
                                          String[] fieldNames, int minWidth, int maxWidth) {
        for (int i = 0; i < columnCount; i++) {
            sheet.autoSizeColumn(i);
            
            int currentWidth = sheet.getColumnWidth(i);
            int charWidth = currentWidth / 256;
            
            if (charWidth < minWidth) {
                sheet.setColumnWidth(i, minWidth * 256);
            } else if (charWidth > maxWidth) {
                sheet.setColumnWidth(i, maxWidth * 256);
            }
            
            int adjustedWidth = sheet.getColumnWidth(i);
            sheet.setColumnWidth(i, adjustedWidth + 512);
        }
    }
    
    private static CellStyle createHeaderStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        
        style.setFillForegroundColor(IndexedColors.SKY_BLUE.getIndex());
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        
        style.setBorderBottom(BorderStyle.MEDIUM);
        style.setBorderTop(BorderStyle.MEDIUM);
        style.setBorderLeft(BorderStyle.MEDIUM);
        style.setBorderRight(BorderStyle.MEDIUM);
        
        Font font = workbook.createFont();
        font.setBold(true);
        font.setFontHeightInPoints((short) 14);
        font.setColor(IndexedColors.WHITE.getIndex());
        style.setFont(font);
        
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setWrapText(true);
        
        return style;
    }
    
    private static CellStyle createDataStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setWrapText(true);
        
        DataFormat format = workbook.createDataFormat();
        style.setDataFormat(format.getFormat("@"));
        
        return style;
    }
    
    private static CellStyle createCustomHeaderStyle(Workbook workbook, ExcelExportConfig config) {
        CellStyle style = workbook.createCellStyle();
        
        if (config.getHeaderBgColor() != null) {
            style.setFillForegroundColor(config.getHeaderBgColor().getIndex());
            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        }
        
        style.setBorderBottom(config.getHeaderBorderStyle());
        style.setBorderTop(config.getHeaderBorderStyle());
        style.setBorderLeft(config.getHeaderBorderStyle());
        style.setBorderRight(config.getHeaderBorderStyle());
        
        Font font = workbook.createFont();
        font.setBold(config.isHeaderBold());
        font.setFontHeightInPoints(config.getHeaderFontSize());
        if (config.getHeaderFontColor() != null) {
            font.setColor(config.getHeaderFontColor().getIndex());
        }
        style.setFont(font);
        
        style.setAlignment(config.getHeaderAlignment());
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setWrapText(config.isWrapText());
        
        return style;
    }
    
    private static CellStyle createCustomDataStyle(Workbook workbook, ExcelExportConfig config) {
        CellStyle style = workbook.createCellStyle();
        
        style.setBorderBottom(config.getDataBorderStyle());
        style.setBorderTop(config.getDataBorderStyle());
        style.setBorderLeft(config.getDataBorderStyle());
        style.setBorderRight(config.getDataBorderStyle());
        
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        
        if (config.getDataAlignment() != null) {
            style.setAlignment(config.getDataAlignment());
        }
        
        style.setWrapText(config.isWrapText());
        
        return style;
    }
    
    private static <T> void fillRowData(Row row, T data, String[] fieldNames, CellStyle style) {
        try {
            for (int i = 0; i < fieldNames.length; i++) {
                Cell cell = row.createCell(i);
                cell.setCellStyle(style);
                
                String fieldName = fieldNames[i];
                Object value = getFieldValue(data, fieldName);
                setCellValue(cell, value);
            }
        } catch (Exception e) {
            throw new RuntimeException("填充行数据失败", e);
        }
    }
    
    private static Object getFieldValue(Object obj, String fieldName) {
        try {
            Field field = getField(obj.getClass(), fieldName);
            if (field == null) return "";
            
            field.setAccessible(true);
            return field.get(obj);
        } catch (Exception e) {
            return "";
        }
    }
    
    private static void setCellValue(Cell cell, Object value) {
        if (value == null) {
            cell.setCellValue("");
        } else if (value instanceof String) {
            cell.setCellValue((String) value);
        } else if (value instanceof Number) {
            if (value instanceof Integer || value instanceof Long || 
                value instanceof Double || value instanceof Float) {
                cell.setCellValue(((Number) value).doubleValue());
            } else if (value instanceof BigDecimal) {
                cell.setCellValue(((BigDecimal) value).doubleValue());
            }
        } else if (value instanceof Date) {
            cell.setCellValue((Date) value);
        } else if (value instanceof Boolean) {
            cell.setCellValue((Boolean) value);
        } else {
            cell.setCellValue(value.toString());
        }
    }
    
    private static <T> Map<Integer, String> parseHeaderAndCreateMapping(Sheet sheet, 
                                                                       ExcelImportConfig<T> config) {
        Map<Integer, String> columnFieldMap = new HashMap<>();
        Row headerRow = sheet.getRow(0);
        
        if (headerRow == null) {
            throw new RuntimeException("Excel文件缺少表头行");
        }
        
        List<String> actualHeaders = new ArrayList<>();
        for (int i = 0; i < headerRow.getLastCellNum(); i++) {
            Cell cell = headerRow.getCell(i);
            String headerName = getCellValueAsString(cell);
            actualHeaders.add(headerName);
        }
        
        if (config.getExpectedHeaders() != null && config.getExpectedHeaders().length > 0) {
            validateHeaders(actualHeaders, config);
        }
        
        if (!config.getIndexMapping().isEmpty()) {
            columnFieldMap.putAll(config.getIndexMapping());
        } else if (!config.getColumnMapping().isEmpty()) {
            for (int i = 0; i < actualHeaders.size(); i++) {
                String headerName = actualHeaders.get(i);
                String fieldName = config.getColumnMapping().get(headerName);
                if (fieldName != null) {
                    columnFieldMap.put(i, fieldName);
                }
            }
        } else {
            for (int i = 0; i < actualHeaders.size(); i++) {
                String headerName = actualHeaders.get(i);
                if (headerName != null && !headerName.trim().isEmpty()) {
                    String fieldName = toCamelCase(headerName.trim());
                    columnFieldMap.put(i, fieldName);
                }
            }
        }
        
        return columnFieldMap;
    }
    
    private static <T> void validateHeaders(List<String> actualHeaders, 
                                           ExcelImportConfig<T> config) {
        String[] expectedHeaders = config.getExpectedHeaders();
        
        if (config.isStrictHeaderCheck()) {
            if (actualHeaders.size() != expectedHeaders.length) {
                throw new RuntimeException(
                    String.format("表头数量不匹配，期望: %d，实际: %d", 
                                expectedHeaders.length, actualHeaders.size()));
            }
            
            for (int i = 0; i < expectedHeaders.length; i++) {
                String expected = expectedHeaders[i];
                String actual = i < actualHeaders.size() ? actualHeaders.get(i) : "";
                if (!expected.equals(actual)) {
                    throw new RuntimeException(
                        String.format("第 %d 列表头不匹配，期望: '%s'，实际: '%s'", 
                                    i+1, expected, actual));
                }
            }
        } else {
            Set<String> actualHeaderSet = new HashSet<>(actualHeaders);
            for (String expected : expectedHeaders) {
                if (!actualHeaderSet.contains(expected)) {
                    throw new RuntimeException("缺少必要表头: " + expected);
                }
            }
        }
    }
    
    private static <T> T parseRowToObject(Row row, Map<Integer, String> columnFieldMap, 
                                         ExcelImportConfig<T> config, String sheetName,
                                         List<ImportErrorDetail> errors) throws Exception {
        T obj = config.getTargetClass().newInstance();
        boolean hasData = false;
        
        for (Map.Entry<Integer, String> entry : columnFieldMap.entrySet()) {
            int columnIndex = entry.getKey();
            String fieldName = entry.getValue();
            
            Cell cell = row.getCell(columnIndex);
            Object cellValue = getCellValue(cell, config);
            
            if (config.getRequiredFields().contains(fieldName) && isEmptyValue(cellValue)) {
                errors.add(new ImportErrorDetail(row.getRowNum(), columnIndex, sheetName, 
                    fieldName, cellValue, "该字段为必填字段", ImportErrorDetail.ErrorType.REQUIRED_ERROR));
                continue;
            }
            
            if (cellValue != null) {
                try {
                    List<String> fieldErrors = performFieldValidation(cellValue, fieldName, 
                        row.getRowNum(), columnIndex, config);
                    
                    if (!fieldErrors.isEmpty()) {
                        for (String errorMsg : fieldErrors) {
                            errors.add(new ImportErrorDetail(row.getRowNum(), columnIndex, sheetName, 
                                fieldName, cellValue, errorMsg, ImportErrorDetail.ErrorType.VALIDATION_ERROR));
                        }
                        continue;
                    }
                    
                    setFieldValueWithValidation(obj, fieldName, cellValue, config, row.getRowNum(), columnIndex, sheetName);
                    hasData = true;
                    
                } catch (ExcelImportException e) {
                    errors.add(new ImportErrorDetail(row.getRowNum(), columnIndex, sheetName, 
                        fieldName, cellValue, e.getMessage(), ImportErrorDetail.ErrorType.DATA_FORMAT_ERROR));
                } catch (Exception e) {
                    errors.add(new ImportErrorDetail(row.getRowNum(), columnIndex, sheetName, 
                        fieldName, cellValue, "字段值设置失败: " + e.getMessage(), 
                        ImportErrorDetail.ErrorType.DATA_FORMAT_ERROR));
                }
            }
        }
        
        return hasData ? obj : null;
    }
    
    private static Object getCellValue(Cell cell, ExcelImportConfig<?> config) {
        if (cell == null) return null;
        
        Object value;
        switch (cell.getCellType()) {
            case STRING:
                value = cell.getStringCellValue();
                if (config.isTrimCellValue() && value != null) {
                    value = value.toString().trim();
                }
                break;
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    value = cell.getDateCellValue();
                } else {
                    value = cell.getNumericCellValue();
                }
                break;
            case BOOLEAN:
                value = cell.getBooleanCellValue();
                break;
            case FORMULA:
                try {
                    value = cell.getNumericCellValue();
                } catch (Exception e) {
                    try {
                        value = cell.getStringCellValue();
                    } catch (Exception e2) {
                        value = cell.getCellFormula();
                    }
                }
                break;
            case BLANK:
                value = null;
                break;
            default:
                value = null;
        }
        
        return value;
    }
    
    private static <T> void setFieldValueWithValidation(T obj, String fieldName, Object value, 
                                                       ExcelImportConfig<T> config, 
                                                       int rowIndex, int columnIndex, String sheetName) {
        try {
            Field field = getField(obj.getClass(), fieldName);
            if (field == null) {
                throw new ExcelImportException("字段不存在", rowIndex, columnIndex,
                    sheetName, fieldName, value);
            }
            
            field.setAccessible(true);
            Class<?> fieldType = field.getType();
            
            CellValueConverter converter = config.getCustomConverters().get(fieldName);
            if (converter != null) {
                value = converter.convert(value, fieldType);
            } else {
                value = convertValueWithValidation(value, fieldType, config, rowIndex, columnIndex, sheetName, fieldName);
            }
            
            field.set(obj, value);
            
        } catch (ExcelImportException e) {
            throw e;
        } catch (Exception e) {
            throw new ExcelImportException("字段值设置失败: " + e.getMessage(), 
                rowIndex, columnIndex, sheetName, fieldName, value, e);
        }
    }
    
    private static Object convertValueWithValidation(Object value, Class<?> targetType, 
                                                    ExcelImportConfig<?> config,
                                                    int rowIndex, int columnIndex, String sheetName, String fieldName) {
        if (value == null) return null;
        
        try {
            if (targetType == String.class) {
                return value.toString();
            } else if (targetType == Integer.class || targetType == int.class) {
                if (value instanceof Number) {
                    return ((Number) value).intValue();
                } else {
                    return Integer.parseInt(value.toString().trim());
                }
            } else if (targetType == Long.class || targetType == long.class) {
                if (value instanceof Number) {
                    return ((Number) value).longValue();
                } else {
                    return Long.parseLong(value.toString().trim());
                }
            } else if (targetType == Double.class || targetType == double.class) {
                if (value instanceof Number) {
                    return ((Number) value).doubleValue();
                } else {
                    return Double.parseDouble(value.toString().trim());
                }
            } else if (targetType == BigDecimal.class) {
                return new BigDecimal(value.toString().trim());
            } else if (targetType == Date.class) {
                if (value instanceof Date) {
                    return value;
                } else {
                    SimpleDateFormat sdf = new SimpleDateFormat(config.getDateFormat());
                    return sdf.parse(value.toString());
                }
            } else if (targetType == Boolean.class || targetType == boolean.class) {
                if (value instanceof Boolean) {
                    return value;
                } else {
                    String strValue = value.toString().toLowerCase();
                    return "true".equals(strValue) || "1".equals(strValue) || "是".equals(strValue);
                }
            }
        } catch (Exception e) {
            throw new ExcelImportException(
                String.format("值转换失败: 值 '%s' 无法转换为 %s", value, targetType.getSimpleName()), 
                rowIndex, columnIndex, sheetName, fieldName, value, e);
        }
        
        return value;
    }
    
    private static <T> List<String> performFieldValidation(Object value, String fieldName, 
                                                          int rowIndex, int columnIndex,
                                                          ExcelImportConfig<T> config) {
        List<String> errors = new ArrayList<>();
        
        FieldValidator validator = config.getFieldValidators().get(fieldName);
        if (validator != null) {
            List<String> validationErrors = validator.validate(value, fieldName, rowIndex, columnIndex);
            if (validationErrors != null) {
                errors.addAll(validationErrors);
            }
        }
        
        return errors;
    }
    
    private static <T> void performBusinessValidation(T obj, int rowIndex, 
                                                     ExcelImportConfig<T> config,
                                                     List<ImportErrorDetail> errors) {
        for (BusinessValidator<T> validator : config.getBusinessValidators()) {
            List<ImportErrorDetail> businessErrors = validator.validate(obj, rowIndex);
            if (businessErrors != null) {
                errors.addAll(businessErrors);
            }
        }
    }
    
    private static boolean isEmptyValue(Object value) {
        if (value == null) return true;
        if (value instanceof String) {
            return ((String) value).trim().isEmpty();
        }
        return false;
    }
    
    private static String toCamelCase(String headerName) {
        String[] parts = headerName.split("[\\s_]+");
        StringBuilder result = new StringBuilder(parts[0].toLowerCase());
        
        for (int i = 1; i < parts.length; i++) {
            if (!parts[i].isEmpty()) {
                result.append(Character.toUpperCase(parts[i].charAt(0)))
                      .append(parts[i].substring(1).toLowerCase());
            }
        }
        
        return result.toString();
    }
    
    private static boolean isEmptyRow(Row row) {
        for (int i = 0; i < row.getLastCellNum(); i++) {
            Cell cell = row.getCell(i);
            if (cell != null) {
                Object value = getCellValueAsString(cell);
                if (value != null && !value.toString().trim().isEmpty()) {
                    return false;
                }
            }
        }
        return true;
    }
    
    private static String getCellValueAsString(Cell cell) {
        if (cell == null) return "";
        switch (cell.getCellType()) {
            case STRING: return cell.getStringCellValue();
            case NUMERIC: 
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    return String.valueOf(cell.getNumericCellValue());
                }
            case BOOLEAN: return String.valueOf(cell.getBooleanCellValue());
            case FORMULA: return cell.getCellFormula();
            default: return "";
        }
    }
    
    private static Field getField(Class<?> clazz, String fieldName) {
        for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
            try {
                return superClass.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                // 继续在父类中查找
            }
        }
        return null;
    }
    
    private static int calculateStartRowFromFixedRow(int page, int pageSize, int fixedStartRow) {
        return fixedStartRow + (page - 1) * pageSize;
    }
    
    private static int calculateEndRowFromFixedRow(Sheet sheet, int startRow, int pageSize, int configEndRow) {
        int endRow = startRow + pageSize - 1;
        int lastRow = Math.min(sheet.getLastRowNum(), configEndRow);
        return Math.min(endRow, lastRow);
    }
    
    private static <T> void processBatch(List<T> batch, StreamingDataProcessor<T> processor, int startIndex) {
        int successCount = 0;
        for (int i = 0; i < batch.size(); i++) {
            T item = batch.get(i);
            try {
                if (processor.processItem(item, startIndex + i)) {
                    successCount++;
                }
            } catch (Exception e) {
                System.err.printf("处理第%d条数据时发生错误: %s%n", startIndex + i, e.getMessage());
            }
        }
        processor.onBatchComplete(batch.size(), successCount);
    }
    
    private static int getMaxColumnCount(Sheet sheet) {
        int maxCols = 0;
        for (int i = 0; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row != null) {
                maxCols = Math.max(maxCols, row.getLastCellNum());
            }
        }
        return maxCols;
    }
    
    private static void closeWorkbook(Workbook workbook) {
        if (workbook != null) {
            try {
                workbook.close();
            } catch (IOException e) {
                // 忽略关闭异常
            }
        }
    }
    
    private static void closeStream(Closeable stream) {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                // 忽略关闭异常
            }
        }
    }
}